package com.hongshu.web.service.web.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hongshu.common.core.enums.AuditStatusEnum;
import com.hongshu.common.core.enums.ResultCodeEnum;
import com.hongshu.common.core.enums.TerminalTypeEnum;
import com.hongshu.common.core.exception.HongshuException;
import com.hongshu.common.core.utils.ConvertUtils;
import com.hongshu.common.core.utils.StringUtils;
import com.hongshu.common.redis.service.RedisService;
import com.hongshu.system.api.RemoteFileService;
import com.hongshu.system.api.RemoteSystemService;
import com.hongshu.web.async.NoteAsyncService;
import com.hongshu.web.auth.AuthContextHolder;
import com.hongshu.web.domain.dto.NoteAppDTO;
import com.hongshu.web.domain.dto.NoteDTO;
import com.hongshu.web.domain.entity.*;
import com.hongshu.web.domain.vo.NoteVo;
import com.hongshu.web.domain.vo.ProductVo;
import com.hongshu.web.mapper.idle.IdleProductMapper;
import com.hongshu.web.mapper.web.WebLikeOrCollectionMapper;
import com.hongshu.web.mapper.web.WebNoteMapper;
import com.hongshu.web.mapper.web.WebProductNoteRelationMapper;
import com.hongshu.web.mapper.web.WebUserMapper;
import com.hongshu.web.service.sys.ISysSystemConfigService;
import com.hongshu.web.service.web.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: hongshu
 */
@Service
public class WebNoteServiceImpl extends ServiceImpl<WebNoteMapper, WebNote> implements IWebNoteService {

    @Autowired
    private IWebUserService userService;
    @Autowired
    private WebUserMapper userMapper;
    @Autowired
    private IWebTagNoteRelationService tagNoteRelationService;
    @Autowired
    private IWebTagService tagService;
    @Autowired
    private IWebCategoryService categoryService;
    //    @Autowired
//    private IWebEsNoteService esNoteService;
    @Autowired
    private IWebFollowerService followerService;
    @Autowired
    private IWebLikeOrCollectionService likeOrCollectionService;
    @Autowired
    private WebLikeOrCollectionMapper likeOrCollectionMapper;
    @Autowired
    private IWebCommentService commentService;
    @Autowired
    private IWebCommentSyncService commentSyncService;
    @Autowired
    private IWebAlbumNoteRelationService albumNoteRelationService;
    @Autowired
    private RemoteFileService remoteFileService;
    @Autowired
    private RemoteSystemService remoteSystemService;
    //    @Autowired
//    private IOssService ossService;
    @Autowired
    private WebProductNoteRelationMapper noteRelationMapper;
    @Autowired
    private WebNoteMapper noteMapper;
    @Autowired
    private IdleProductMapper productMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private NoteAsyncService noteAsyncService;
    @Autowired
    private ISysSystemConfigService systemConfigService;


    @NotNull
    private StringBuilder getTags(WebNote note, NoteDTO noteDTO) {
        List<String> tagList = noteDTO.getTags();
        List<WebTagNoteRelation> tagNoteRelationList = new ArrayList<>();
        List<WebTag> tagList1 = tagService.list();
        Map<String, WebTag> tagMap = tagList1.stream().collect(Collectors.toMap(WebTag::getTitle, tag -> tag));
        StringBuilder tags = new StringBuilder();
        if (!tagList.isEmpty()) {
            for (String tag : tagList) {
                WebTagNoteRelation tagNoteRelation = new WebTagNoteRelation();
                if (tagMap.containsKey(tag)) {
                    WebTag tagModel = tagMap.get(tag);
                    tagNoteRelation.setTid(String.valueOf(tagModel.getId()));
                } else {
                    WebTag model = new WebTag();
                    model.setTitle(tag);
                    model.setLikeCount(1L);
                    tagService.save(model);
                    tagNoteRelation.setTid(String.valueOf(model.getId()));
                }
                tagNoteRelation.setNid(String.valueOf(note.getId()));
                tagNoteRelationList.add(tagNoteRelation);
                tags.append(tag);
            }
            tagNoteRelationService.saveBatch(tagNoteRelationList);
        }
        return tags;
    }

    /**
     * 获取笔记
     *
     * @param noteId 笔记ID
     */
    @Override
    public NoteVo getNoteById(String noteId) {
        WebNote note = this.getById(noteId);
        if (note == null) {
            throw new HongshuException(ResultCodeEnum.FAIL);
        }
        note.setViewCount(note.getViewCount() + 1);
        WebUser user = userService.getById(note.getUid());
        NoteVo noteVo = ConvertUtils.sourceToTarget(note, NoteVo.class);
        // 处理位置信息
        if (noteVo.getLocation() == null || noteVo.getLocation().isEmpty()) {
            noteVo.setLocation(noteVo.getLocation());
        } else {
            noteVo.setLocation(noteVo.getLocation().split(" ")[0]);
        }
        noteVo.setUsername(user.getUsername())
                .setAvatar(user.getAvatar())
                .setTime(note.getUpdateTime().getTime());
        // 处理关注状态
        boolean follow = followerService.isFollow(String.valueOf(user.getId()));
        noteVo.setIsFollow(follow);
        // 处理点赞收藏状态
//        String currentUid = WebUtils.getRequestHeader(UserConstant.USER_ID);
        String currentUid = AuthContextHolder.getUserId();
        List<WebLikeOrCollection> likeOrCollectionList = likeOrCollectionService.list(
                new QueryWrapper<WebLikeOrCollection>()
                        .eq("like_or_collection_id", noteId)
                        .eq("uid", currentUid)
        );
        Set<Integer> types = likeOrCollectionList.stream()
                .map(WebLikeOrCollection::getType)
                .collect(Collectors.toSet());
        noteVo.setIsLike(types.contains(1));
        noteVo.setIsCollection(types.contains(3));
        // 处理标签
        List<WebTagNoteRelation> tagNoteRelationList = tagNoteRelationService.list(
                new QueryWrapper<WebTagNoteRelation>().eq("nid", noteId)
        );
        List<String> tids = tagNoteRelationList.stream()
                .map(WebTagNoteRelation::getTid)
                .collect(Collectors.toList());
        if (!tids.isEmpty()) {
            List<WebTag> tagList = tagService.listByIds(tids);
            noteVo.setTagList(tagList);
        }
        // 处理关联商品信息
        if (StringUtils.isNotBlank(note.getProductId())) {
            List<String> productIds = Arrays.asList(note.getProductId().split(","));
            List<IdleProduct> products = productMapper.selectBatchIds(productIds);
            List<ProductVo> productVos = products.stream()
                    .map(product -> {
                        ProductVo vo = new ProductVo();
                        vo.setId(product.getId());
                        vo.setTitle(product.getTitle());
                        vo.setCover(product.getCover());
                        vo.setPrice(product.getPrice());
                        vo.setOriginalPrice(product.getOriginalPrice());
                        // 设置销量信息
//                        vo.setSoldCount(product.getSoldCount());
                        return vo;
                    })
                    .collect(Collectors.toList());
            noteVo.setRelatedProducts(productVos);
        }
//        this.updateById(note);
        return noteVo;
    }

    /**
     * 新增笔记
     *
     * @param terminal  来源标识
     * @param requestId 唯一标识
     * @param noteData  笔记对象
     * @param coverFile 封面图
     * @param files     图片文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveNoteByDTO(String terminal, String requestId, String noteData, MultipartFile coverFile, MultipartFile[] files) {
        // 幂等性校验，防止重复提交
        String redisKey = "note:save:" + requestId;
        if (Boolean.TRUE.equals(redisService.hasKey(redisKey))) {
            throw new RuntimeException("请勿重复提交");
        }
        // 设置标记，5分钟后自动过期
        redisService.setCacheObject(redisKey, "1", 5L, TimeUnit.MINUTES);

        // 保存封面到本地临时目录
        String coverLocalPath = this.saveToLocalTemp(coverFile);
        // 保存内容文件到本地临时目录
        List<String> fileLocalPaths = new ArrayList<>();
        for (MultipartFile file : files) {
            fileLocalPaths.add(this.saveToLocalTemp(file));
        }

        // 调用异步处理
        String currentUid = AuthContextHolder.getUserId();
        noteAsyncService.addNote(terminal, currentUid, noteData, coverLocalPath, fileLocalPaths);
    }

    @Override
    @Transactional
    public void saveNote(String terminal, String requestId, NoteAppDTO noteDTO) {
        if ("1".equals(noteDTO.getNoteType())) {
            // 图片类型
            if (noteDTO.getUrls() == null) {
                throw new RuntimeException("未上传任何图片");
            }
        } else if ("2".equals(noteDTO.getNoteType())) {
            // 视频类型
            if (noteDTO.getUrls() == null) {
                throw new RuntimeException("请上传一个视频文件");
            }
        }
        // 幂等性校验，防止重复提交
        String redisKey = "note:save:" + requestId;
        if (Boolean.TRUE.equals(redisService.hasKey(redisKey))) {
            throw new RuntimeException("请勿重复提交");
        }
        // 设置标记，5分钟后自动过期
        redisService.setCacheObject(redisKey, "1", 5L, TimeUnit.MINUTES);

        String currentUid = AuthContextHolder.getUserId();
        try {
            // 更新用户笔记数量
            WebUser user = userMapper.selectById(currentUid);
            user.setNoteCount(user.getNoteCount() + 1);
            user.setUpdateTime(new Date());
            userMapper.updateById(user);

            // 保存笔记
            WebNote note = ConvertUtils.sourceToTarget(noteDTO, WebNote.class);
            note.setUid(currentUid);
            note.setAuthor(user.getUsername());
            String tags = JSONUtil.toJsonStr(noteDTO.getTags().toArray(new String[0]));
            note.setTags(tags);
            String urls = JSONUtil.toJsonStr(noteDTO.getUrls().toArray());
            note.setUrls(urls);
            note.setFromType(TerminalTypeEnum.fromValue(terminal).getCode());
            // 查询审核开关，是否开启审核
            Boolean auditEnabled = systemConfigService.getSystemConfig().getContentAuditEnabled();
            if (auditEnabled) {
                note.setAuditStatus(AuditStatusEnum.REVIEW.getCode());
            } else {
                note.setAuditStatus(AuditStatusEnum.PASS.getCode());
            }
            note.setCreator(user.getUsername());
            note.setTime(System.currentTimeMillis());
            note.setCreateTime(new Date());
            note.setUpdateTime(new Date());
            // 保存笔记
            noteMapper.insert(note);
        } catch (Exception e) {
            log.error("笔记保存失败", e);
            throw new RuntimeException("笔记保存失败: " + e.getMessage());
        }
    }

    /**
     * 保存文件到本地临时目录
     */
    private String saveToLocalTemp(MultipartFile file) {
        String tempDir = System.getProperty("java.io.tmpdir");
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        File localFile = new File(tempDir, fileName);
        try {
            file.transferTo(localFile);
        } catch (IOException e) {
            throw new RuntimeException("文件保存失败", e);
        }
        return localFile.getAbsolutePath();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNoteByDTO(String noteData, MultipartFile coverFile, MultipartFile[] files) {
        String currentUid = AuthContextHolder.getUserId();
        // 解析前端传来的数据
        NoteDTO noteDTO = JSONUtil.toBean(noteData, NoteDTO.class);
        // 查询原有笔记
        WebNote note = noteMapper.selectById(noteDTO.getId());
        if (note == null) {
            throw new RuntimeException("笔记不存在");
        }
        if (!note.getUid().equals(currentUid)) {
            throw new RuntimeException("无权编辑该笔记");
        }

        // 保存封面到本地临时目录
        String coverLocalPath = this.saveToLocalTemp(coverFile);
        // 保存内容文件到本地临时目录
        List<String> fileLocalPaths = new ArrayList<>();
        for (MultipartFile file : files) {
            fileLocalPaths.add(this.saveToLocalTemp(file));
        }

        // 调用异步处理
        noteAsyncService.updateNote(noteDTO, note, coverLocalPath, fileLocalPaths);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteNoteByIds(List<String> noteIds) {
        List<WebNote> noteList = this.listByIds(noteIds);
        // TODO 这里需要优化，数据一致性问题
        noteList.forEach(item -> {
            String noteId = item.getId();
//            esNoteService.deleteNote(noteId);

            String urls = item.getUrls();
            JSONArray objects = JSONUtil.parseArray(urls);
            Object[] array = objects.toArray();
            List<String> pathArr = new ArrayList<>();
            for (Object o : array) {
                pathArr.add((String) o);
            }
//            ossService.batchDelete(pathArr);
            // TODO 可以使用多线程优化，
            // 删除点赞图片，评论，标签关系，收藏关系
            likeOrCollectionService.remove(new QueryWrapper<WebLikeOrCollection>().eq("like_or_collection_id", noteId));
            List<WebComment> commentList = commentService.list(new QueryWrapper<WebComment>().eq("nid", noteId));
            List<WebCommentSync> commentSyncList = commentSyncService.list(new QueryWrapper<WebCommentSync>().eq("nid", noteId));
            List<String> cids = commentList.stream().map(WebComment::getId).collect(Collectors.toList());
            List<String> cids2 = commentSyncList.stream().map(WebCommentSync::getId).collect(Collectors.toList());
            if (!cids.isEmpty()) {
                likeOrCollectionService.remove(new QueryWrapper<WebLikeOrCollection>().in("like_or_collection_id", cids).eq("type", 2));
            }
            commentService.removeBatchByIds(cids);
            commentSyncService.removeBatchByIds(cids2);
            tagNoteRelationService.remove(new QueryWrapper<WebTagNoteRelation>().eq("nid", noteId));
            albumNoteRelationService.remove(new QueryWrapper<WebAlbumNoteRelation>().eq("nid", noteId));
        });
        this.removeBatchByIds(noteIds);
    }

    @Override
    public Page<NoteVo> getHotPage(long currentPage, long pageSize) {
        return null;
    }

    @Override
    public boolean pinnedNote(String noteId) {
//        String currentUid = WebUtils.getRequestHeader(UserConstant.USER_ID);
        String currentUid = AuthContextHolder.getUserId();
        WebNote note = this.getById(noteId);
        if ("1".equals(note.getPinned())) {
            note.setPinned("0");
        } else {
            List<WebNote> noteList = this.list(new QueryWrapper<WebNote>().eq("uid", currentUid));
            long count = noteList.stream().filter(item -> "1".equals(item.getPinned())).count();
            if (count >= 3) {
                throw new HongshuException("最多只能置顶3个笔记");
            }
            note.setPinned("1");
            note.setUpdateTime(new Date());
        }
        return this.updateById(note);
    }

    @Override
    public Object getNoteCount(String userId) {
        int allCount = Math.toIntExact(noteMapper.selectCount(
                new QueryWrapper<WebNote>()
                        .eq("uid", userId)));
        int pendingCount = Math.toIntExact(noteMapper.selectCount(
                new QueryWrapper<WebNote>()
                        .eq("uid", userId)
                        .eq("audit_status", AuditStatusEnum.REVIEW.getCode())));
        int approvedCount = Math.toIntExact(noteMapper.selectCount(
                new QueryWrapper<WebNote>()
                        .eq("uid", userId)
                        .eq("audit_status", AuditStatusEnum.PASS.getCode())));
        int rejectedCount = Math.toIntExact(noteMapper.selectCount(
                new QueryWrapper<WebNote>()
                        .eq("uid", userId)
                        .eq("audit_status", AuditStatusEnum.REJECT.getCode())));
        // 新增：统计被点赞数
        List<Object> noteIds = noteMapper.selectObjs(
                new QueryWrapper<WebNote>().select("id").eq("uid", userId)
        );
        int likeCount = 0;
        if (!noteIds.isEmpty()) {
            likeCount = Math.toIntExact(likeOrCollectionMapper.selectCount(
                    new QueryWrapper<WebLikeOrCollection>().in("like_or_collection_id", noteIds)
            ));
        }

        Map<String, Object> result = new HashMap<>(3);
        result.put("allCount", allCount);
        result.put("pendingCount", pendingCount);
        result.put("approvedCount", approvedCount);
        result.put("rejectedCount", rejectedCount);
        result.put("likeCount", likeCount);
        return result;
    }
}
